import React from 'react';
import L from 'leaflet';
import 'leaflet.migration';
import { withLeaflet } from 'react-leaflet';
import { debounce, isEmpty } from 'lodash';
import setting from './setting';

function isLngLat(lngLat) {
  if (!Array.isArray(lngLat)) return false;
  const lng = lngLat[0];
  const lat = lngLat[1];
  return Number(lng) && Math.abs(Number(lng)) > 0 && Math.abs(Number(lng)) < 180
    && Number(lat) && Math.abs(Number(lat)) > 0 && Math.abs(Number(lat)) < 90;
}

class FlyLine extends React.PureComponent {
  reloadMap = debounce(() => {
    const { leaflet: { map } } = this.props;
    if (this.mapData.length === 0) {
      map.removeLayer(this.leafletElement);
      this.leafletElement = null;
    } else if (!this.leafletElement) {
      this.initMap();
    } else {
      this.leafletElement.setData(this.mapData);
      this.leafletElement.setStyle(this.mapStyle);
    }
  }, 1000);

  constructor(props) {
    super(props);
    this.initMap();
    this.cacheStringify = this.propsStringify;
  }

  componentDidUpdate() {
    const { propsStringify } = this;
    if (this.cacheStringify !== propsStringify) {
      this.cacheStringify = propsStringify;
      this.reloadMap();
    }
  }

  componentWillUnmount() {
    if (!this.leafletElement) return;
    const { leaflet: { map } } = this.props;
    map.removeLayer(this.leafletElement);
  }

  get baseStyle() {
    const { config: { base } } = this.props;

    return base;
  }

  get tooltip() {
    const { config: { tooltip } } = this.props;
    return tooltip;
  }

  get propsStringify() {
    const { config, data } = this.props;
    return JSON.stringify({ config, data });
  }

  /**
   * @return {array} [{
   *                  "from": [-118.2705, 33.9984],
   *                  "to": [-122.789336, 37.920458],
   *                  "labels": ["Los Angeles", "San Francisco"],
   *                  "color": "#ff3a31",
   *                  "value": 15
   *                }]
   */
  get mapData() {
    const { data } = this.props;
    const { color } = this.baseStyle;

    if (!isEmpty(data)) {
      const realData = data.map(line => (
        {
          ...line,
          labels: line.labels ? line.labels.split(',') : '',
          to: line.labels ? line.to.split(',') : '',
          from: line.labels ? line.from.split(',') : '',
          value: this.getIconSize(line.value)
        }
      ));

      return realData.filter(item => isLngLat(item.from) && isLngLat(item.to))
        .map(item => ({ color, ...item }));
    }
    return [];
  }

  get mapStyle() {
    const { direction, maxSize, minSize } = this.baseStyle;

    return {
      pulseRadius: Math.floor(minSize / 2 + maxSize / 2),
      arcWidth: 1,
      label: true,
      direction,
      replacePopover: (x, y, data) => {
        if (this.tooltip.show === 'hover' && data.tooltip) {
          return this.getIconDiv(data);
        }
        return document.createElement('div');
      }
    };
  }

  // 获得经纬度点位数组的value边界
  get valueBound() {
    const { data } = this.props;
    const values = data.map(item => item.value || 1);
    return {
      valueMax: Math.max(...values),
      valueMin: Math.min(...values)
    };
  }

  getIconSize = (value) => {
    const { maxSize, minSize } = this.baseStyle;

    const { valueMax, valueMin } = this.valueBound;
    if (valueMax === valueMin) return (maxSize + minSize) / 2;

    return Math.floor((maxSize - minSize) * (value - valueMin)
      / (valueMax - valueMin) + minSize);
  };

  getIconDiv = (data) => {
    const {
      font, borderWidth, borderColor, backgroundColor
    } = this.tooltip;
    const tipDiv = document.createElement('div');
    tipDiv.innerHTML = data.tooltip;

    tipDiv.className = 'map-marker-content';

    tipDiv.style.fontFamily = font.fontFamily;
    tipDiv.style.fontWeight = font.fontWeight;
    tipDiv.style.fontSize = `${font.fontSize}px`;
    tipDiv.style.color = font.color;
    tipDiv.style.border = `${borderWidth}px solid ${borderColor}`;
    tipDiv.style.backgroundColor = backgroundColor;

    return tipDiv;
  };

  initMap() {
    const { leaflet: { map } } = this.props;
    this.leafletElement = L.migrationLayer(
      this.mapData,
      this.mapStyle
    );
    this.leafletElement.addTo(map);
  }

  render() {
    return null;
  }
}
FlyLine.setting = setting;

export default withLeaflet(FlyLine);
